package com.sf.business.process.service.impl;

import com.sf.business.appointment.domain.BusServiceItem;
import com.sf.business.appointment.mapper.BusServiceItemMapper;
import com.sf.business.process.domain.BusBpmnInfo;
import com.sf.business.process.mapper.BusBpmnInfoMapper;
import com.sf.business.process.service.IBusBpmnInfoService;
import com.sf.business.process.vo.BusBpmnInfoVO;
import com.sf.common.utils.file.FileUploadUtils;
import io.jsonwebtoken.lang.Assert;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;

/**
 * 流程定义明细Service业务层处理
 *
 * @author lh
 * @date 2025-03-26
 */
@Service
public class BusBpmnInfoServiceImpl implements IBusBpmnInfoService {
    @Autowired
    private BusBpmnInfoMapper busBpmnInfoMapper;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private BusServiceItemMapper busServiceItemMapper;

    /**
     * 查询流程定义明细
     *
     * @param id 流程定义明细主键
     * @return 流程定义明细
     */
    @Override
    public BusBpmnInfo selectBusBpmnInfoById(Long id) {
        return busBpmnInfoMapper.selectBusBpmnInfoById(id);
    }

    /**
     * 查询流程定义明细列表
     *
     * @param busBpmnInfo 流程定义明细
     * @return 流程定义明细
     */
    @Override
    public List<BusBpmnInfo> selectBusBpmnInfoList(BusBpmnInfo busBpmnInfo) {
        return busBpmnInfoMapper.selectBusBpmnInfoList(busBpmnInfo);
    }

    /**
     * 新增流程定义明细
     *
     * @param busBpmnInfo 流程定义明细
     * @return 结果
     */
    @Override
    public int insertBusBpmnInfo(BusBpmnInfo busBpmnInfo) {
        return busBpmnInfoMapper.insertBusBpmnInfo(busBpmnInfo);
    }

    /**
     * 修改流程定义明细
     *
     * @param busBpmnInfo 流程定义明细
     * @return 结果
     */
    @Override
    public int updateBusBpmnInfo(BusBpmnInfo busBpmnInfo) {
        return busBpmnInfoMapper.updateBusBpmnInfo(busBpmnInfo);
    }

    /**
     * 批量删除流程定义明细
     *
     * @param id 需要删除的流程定义明细主键
     * @return 结果
     */
    @Override
    public int deleteBusBpmnInfoByIds(Long id) {
        return busBpmnInfoMapper.deleteBusBpmnInfoById(id);
    }

    /**
     * 删除流程定义明细信息
     *
     * @param id 流程定义明细主键
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteBusBpmnInfoById(Long id) {
        // 1. 数据判空
        BusBpmnInfo busBpmnInfo = busBpmnInfoMapper.selectBusBpmnInfoById(id);
        Assert.notNull(busBpmnInfo, "数据不存在");

        // 2. 将服务项表 bus_statement_item 表中审核状态修改为 [初始化] (如果是审核中的状态)
        List<ProcessInstance> instanceList = runtimeService.createProcessInstanceQuery()
                .processDefinitionKey(busBpmnInfo.getProcessDefinitionKey())
                .processDefinitionVersion(busBpmnInfo.getVersion().intValue())
                .list();
        if (instanceList.size() > 0) {
            for (ProcessInstance instance : instanceList) {

                String businessKey = instance.getBusinessKey();
                BusServiceItem busServiceItem = busServiceItemMapper.selectBusServiceItemById(Long.parseLong(businessKey));
                Assert.notNull(busServiceItem, "服务项数据不存在");

                if (busServiceItem.getAuditStatus() == 1) {
                    busServiceItem.setAuditStatus(0);
                    busServiceItemMapper.updateBusServiceItem(busServiceItem);
                }
            }
        }

        // 3. 删除流程定义和流程实例
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(busBpmnInfo.getProcessDefinitionKey())
                .processDefinitionVersion(busBpmnInfo.getVersion().intValue())
                .singleResult();

        repositoryService.deleteDeployment(processDefinition.getDeploymentId(), true);

        // 4. 删除 bus_bpmn_info 表中数据
        busBpmnInfoMapper.deleteBusBpmnInfoById(id);

        return 1;
    }

    @Override
    public int flow(MultipartFile file, BusBpmnInfoVO vo) {
        try {
            // 1. 非空校验 (参数 / 文件)
            Assert.notNull(file, "文件不能为空");
            Assert.notNull(vo.getBpmnLabel(), "文件类型不能为空");
            Assert.notNull(vo.getBpmnType(), "流程类型不能为空");
            Assert.notNull(vo.getInfo(), "文件信息不能为空");

            if (file.getSize() == 0)
                throw new IllegalArgumentException("文件不能为空");

            // 2. 判断文件类型是否为 bpmn
            if (!FileUploadUtils.getExtension(file).equals("bpmn"))
                throw new IllegalArgumentException("文件类型错误");

            // 3. 部署 流程图
            Deployment deploy = repositoryService.createDeployment().addInputStream(vo.getBpmnLabel(), file.getInputStream()).deploy();

            // 4. 保存信息到 bus_bpmn_info 表中
            BusBpmnInfo busBpmnInfo = new BusBpmnInfo();
            busBpmnInfo.setBpmnLabel(vo.getBpmnLabel());
            busBpmnInfo.setBpmnType(vo.getBpmnType());
            busBpmnInfo.setInfo(vo.getInfo());
            busBpmnInfo.setDeployTime(deploy.getDeploymentTime());

            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult();
            busBpmnInfo.setProcessDefinitionKey(processDefinition.getKey());
            busBpmnInfo.setVersion((long) processDefinition.getVersion());

            busBpmnInfoMapper.insertBusBpmnInfo(busBpmnInfo);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return 1;
    }

    @Override
    public InputStream getResource(String type, Long id) {
        // 1. 依旧是 参数判空
        Assert.notNull(type, "文件类型不能为空");
        Assert.notNull(id, "文件id不能为空");

        // 2. 根据 id 判断 bpmnInfo 表中是否有对应数据
        BusBpmnInfo busBpmnInfo = busBpmnInfoMapper.selectBusBpmnInfoById(id);
        Assert.notNull(busBpmnInfo, "文件信息不存在");

        // 2. 根据 id 查询流程定义信息
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(busBpmnInfo.getProcessDefinitionKey())
                .processDefinitionVersion(busBpmnInfo.getVersion().intValue()).singleResult();

        if (type.equals("xml")) {
            return repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
        } else if (type.equals("png")) {
            DefaultProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());


            /**
             * 第一个参数: 流程定义模型
             * 第二个参数: 高亮节点集合
             * 第三个参数: 高亮连线集合
             */
            InputStream inputStream = processDiagramGenerator.generateDiagram(
                    bpmnModel,
                    Collections.emptyList(),
                    Collections.emptyList(),
                    "宋体",
                    "宋体",
                    "宋体");
            return inputStream;
        } else  {
            throw new IllegalArgumentException("文件类型错误");
        }
    }
}
